import * as THREE from "three"
import CopyShader from "../shader/CopyShader"
import ShaderPass from "./ShaderPass"
import { ClearMaskPass, MaskPass } from "./MaskPass"
import RenderPass from "./RenderPass"
export default class EffectComposer {
  renderer: THREE.WebGLRenderer | THREE.WebGL1Renderer
  _pixelRatio: number
  _width: number
  _height: number
  renderTarget1: THREE.WebGLRenderTarget
  renderTarget2: THREE.WebGLRenderTarget
  writeBuffer: THREE.WebGLRenderTarget
  readBuffer: THREE.WebGLRenderTarget
  renderToScreen: boolean
  passes: RenderPass[]
  copyPass: ShaderPass
  clock: THREE.Clock

  constructor(e: THREE.WebGLRenderer | THREE.WebGL1Renderer, t?: THREE.WebGLRenderTarget) {
    this.renderer = e
    if (!t) {
      const s = {
        minFilter: THREE.LinearFilter,
        magFilter: THREE.LinearFilter,
        format: THREE.RGBAFormat
      }
      const i = e.getSize(new THREE.Vector2())
      this._pixelRatio = e.getPixelRatio()
      this._width = i.width
      this._height = i.height
      t = new THREE.WebGLRenderTarget(this._width * this._pixelRatio, this._height * this._pixelRatio, s)
      t.texture.name = "EffectComposer.rt1"
    } else {
      this._pixelRatio = 1
      this._width = t.width
      this._height = t.height
    }
    this.renderTarget1 = t
    this.renderTarget2 = t.clone()
    this.renderTarget2.texture.name = "EffectComposer.rt2"
    this.writeBuffer = this.renderTarget1
    this.readBuffer = this.renderTarget2
    this.renderToScreen = !0
    this.passes = []
    !CopyShader && console.error("THREE.EffectComposer relies on CopyShader")
    !ShaderPass && console.error("THREE.EffectComposer relies on ShaderPass")
    this.copyPass = new ShaderPass(CopyShader)
    this.clock = new THREE.Clock()
  }
  swapBuffers() {
    const e = this.readBuffer
    this.readBuffer = this.writeBuffer
    this.writeBuffer = e
  }
  addPass(e: RenderPass) {
    this.passes.push(e)
    e.setSize()
  }
  insertPass(e: RenderPass, t: number) {
    this.passes.splice(t, 0, e)
    e.setSize()
  }
  removePass(e: RenderPass) {
    const t = this.passes.indexOf(e)
    ;-1 !== t && this.passes.splice(t, 1)
  }
  isLastEnabledPass(e: number) {
    for (let t = e + 1; t < this.passes.length; t++) if (this.passes[t].enabled) return !1
    return !0
  }
  render(e) {
    void 0 === e && (e = this.clock.getDelta())
    const t = this.renderer.getRenderTarget()
    let s = !1
    for (let t = 0, r = this.passes.length; t < r; t++) {
      const r = this.passes[t]
      if (!1 !== r.enabled) {
        r.renderToScreen = this.renderToScreen && this.isLastEnabledPass(t)
        r.render(this.renderer, this.writeBuffer, this.readBuffer)
        if (r.needsSwap) {
          if (s) {
            const t = this.renderer.getContext()
            const s = this.renderer.state.buffers.stencil
            s.setFunc(t.NOTEQUAL, 1, 4294967295)
            this.copyPass.render(this.renderer, this.writeBuffer, this.readBuffer)
            s.setFunc(t.EQUAL, 1, 4294967295)
          }
          this.swapBuffers()
        }
        void 0 !== MaskPass && (r instanceof MaskPass ? (s = !0) : r instanceof ClearMaskPass && (s = !1))
      }
    }
    this.renderer.setRenderTarget(t)
  }
  reset(e) {
    if (void 0 === e) {
      const t = this.renderer.getSize(new THREE.Vector2())
      this._pixelRatio = this.renderer.getPixelRatio()
      this._width = t.width
      this._height = t.height
      e = this.renderTarget1.clone()
      e.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio)
    }
    this.renderTarget1.dispose()
    this.renderTarget2.dispose()
    this.renderTarget1 = e
    this.renderTarget2 = e.clone()
    this.writeBuffer = this.renderTarget1
    this.readBuffer = this.renderTarget2
  }
  setSize(e: number, t: number) {
    this._width = e
    this._height = t
    const s = this._width * this._pixelRatio
    const r = this._height * this._pixelRatio
    this.renderTarget1.setSize(s, r)
    this.renderTarget2.setSize(s, r)
    for (let e = 0; e < this.passes.length; e++) this.passes[e].setSize()
  }
  setPixelRatio(e: number) {
    this._pixelRatio = e
    this.setSize(this._width, this._height)
  }
}
